package com.pan.api.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

enum PanReflectUtilImpl implements PanReflectUtil {
    INSTANCE;

    @Override
    public final Class loadClass(String fullName) {
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        try {
            Class<?> clazz = systemClassLoader.loadClass(fullName);
            return clazz;
        } catch (ClassNotFoundException e) {
            //load class error
            throw new RuntimeException(e);
        }
    }

    @Override
    public final <T> T createNewInstance(Class<T> clazz, Object... args) {
//        Class[] paramTypes = Arrays.stream(args).map(arg -> arg.getClass()).toArray(Class[]::new);
        Constructor<T>[] constructors = (Constructor<T>[]) clazz.getConstructors();
        StringBuffer exceptionInfoCache = new StringBuffer();
        for (Constructor<T> cs : constructors) {
            if (cs.getParameters().length == args.length) {
                try {
                    return cs.newInstance(args);
                } catch (InvocationTargetException
                         | InstantiationException
                         | IllegalAccessException e) {
                    // new instance error
                    exceptionInfoCache.append(e.getMessage());
                    exceptionInfoCache.append("\n");
                }
            }
        }
        String errorMsg = "No Such Method Exception: " + clazz.getName() + ".<init>(" + Arrays.toString(args) + ")";
        exceptionInfoCache.append(errorMsg);
        throw new RuntimeException(exceptionInfoCache.toString());
    }

    @Override
    public final <T> T createNewInstance(String fullName, Object... args) {
        Class<T> clazz = loadClass(fullName);
        return createNewInstance(clazz, args);
    }

}
